home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////////////////////////////
- //
- // ALU.cxx - Arithmetic Logic Unit
- //
- // NOTE: This code is based on the Hector simulator code written
- // by Greg DeHoogh on 17 February 1990.
- //
- // By: Bradford W. Mott
- // December 4,1993
- //
- ///////////////////////////////////////////////////////////////////////////////
-
- #include "ALU.hxx"
-
- ///////////////////////////////////////////////////////////////////////////////
- // Compute a result with the given function and inputs
- ///////////////////////////////////////////////////////////////////////////////
- unsigned long ALU::Compute(ALUFunction fn, unsigned long a_bus,
- unsigned long b_bus)
- {
- unsigned long result;
-
- switch (fn)
- {
- case ADD:
- case ADD_NCC:
- result = a_bus + b_bus;
- break;
-
- case ADDC:
- if(flags & C_FLAG)
- result = a_bus + b_bus + 1;
- else
- result = a_bus + b_bus;
- break;
-
- case SUB:
- case SUB_NCC:
- case CMP:
- result = b_bus - a_bus;
- break;
-
- case AND:
- result = a_bus & b_bus;
- break;
-
- case SUBC:
- if(flags & C_FLAG)
- result = b_bus - a_bus - 1;
- else
- result = b_bus - a_bus;
- break;
-
- case OR:
- result = a_bus | b_bus;
- break;
-
- case XOR:
- result = a_bus ^ b_bus;
- break;
-
- case NOT_A:
- result = ~a_bus;
- break;
-
- case NEG_A:
- result = -a_bus;
- // Set the Carry Flag
- if((result % 0x10000) == 0)
- flags |= C_FLAG;
- else
- flags &= ~C_FLAG;
-
- // Set the Overflow Flag
- if(a_bus == 0x8000)
- flags |= V_FLAG;
- else
- flags &= ~V_FLAG;
- break;
-
- case INC_A:
- result = a_bus + 1;
- // Set the Carry Flag
- if((result % 0x10000) == 0)
- flags |= C_FLAG;
- else
- flags &= ~C_FLAG;
-
- // Set the Overflow Flag
- if(a_bus == 0x8000)
- flags |= V_FLAG;
- else
- flags &= ~V_FLAG;
- break;
-
- case INC_A_NCC:
- result = a_bus + 1;
- break;
-
- case INC_B_NCC:
- result = b_bus + 1;
- break;
-
- case DEC_A:
- result = a_bus - 1;
- // Set the Carry Flag
- if(a_bus == 0)
- flags |= C_FLAG;
- else
- flags &= ~C_FLAG;
-
- // Set the Overflow Flag
- if(a_bus == 0x8000)
- flags |= V_FLAG;
- else
- flags &= ~V_FLAG;
- break;
-
- case DEC_A_NCC:
- result = a_bus - 1;
- break;
-
- case DEC_B_NCC:
- result = b_bus - 1;
- break;
-
- case SHL_A:
- result = a_bus << 1;
- // Set the Carry Flag
- if(a_bus & 0x8000)
- flags |= C_FLAG;
- else
- flags &= ~C_FLAG;
- break;
-
- case ROL_A:
- if(flags & C_FLAG)
- result = (a_bus << 1) | 1;
- else
- result = a_bus << 1;
-
- // Set the Carry Flag
- if(a_bus & 0x8000)
- flags |= C_FLAG;
- else
- flags &= ~C_FLAG;
- break;
-
- case SHR_A:
- result = (a_bus >> 1) | (a_bus & 0x8000);
-
- // Set the Carry Flag
- if(a_bus & 1)
- flags |= C_FLAG;
- else
- flags &= ~C_FLAG;
- break;
-
- case ROR_A:
- if(flags & C_FLAG)
- result = (a_bus >> 1) | 0x8000;
- else
- result = a_bus >> 1;
-
- // Set the Carry Flag
- if(a_bus & 1)
- flags |= C_FLAG;
- else
- flags &= ~C_FLAG;
- break;
-
- case BTST:
- result = a_bus & b_bus;
- break;
-
- case PASS_A:
- case PASS_A_NCC:
- result = a_bus;
- break;
-
- case SWAP_A:
- result = (a_bus >> 8) + ((a_bus & 0x00ff) << 8);
- break;
-
- case CC_OUT:
- result = flags;
- break;
-
- case A_CC:
- flags = a_bus & 0xf800;
- result = 0;
- break;
-
- default:
- result = 0;
- }
-
- /* Set the flags that were not set above */
- switch (fn) {
- case ADD:
- case ADDC:
- case SUB:
- case SUBC:
- case CMP:
- // Set the Carry Flag
- if(result > 0xffff)
- flags |= C_FLAG;
- else
- flags &= ~C_FLAG;
-
- // Set the Negative Flag
- if(result & 0x8000)
- flags |= N_FLAG;
- else
- flags &= ~N_FLAG;
-
- // Set the Zero Flag
- if(result & 0xffff)
- flags &= ~Z_FLAG;
- else
- flags |= Z_FLAG;
-
- switch (fn) {
- case ADD:
- case ADDC:
- // Set the Overflow Flag
- if (((a_bus & 0x8000) == (b_bus & 0x8000)) &&
- ((a_bus & 0x8000) != (result & 0x8000)))
- flags |= V_FLAG;
- else
- flags &= ~V_FLAG;
- break;
-
- case SUB:
- case SUBC:
- case CMP:
- // Set the Overflow flag
- if (((a_bus & 0x8000) != (b_bus & 0x8000)) &&
- ((a_bus & 0x8000) == (result & 0x8000)))
- flags |= V_FLAG;
- else
- flags &= ~V_FLAG;
-
- default:
- break;
- }
- break;
-
- case AND:
- case OR:
- case XOR:
- case NOT_A:
- case NEG_A:
- case INC_A:
- case DEC_A:
- case BTST:
- case SWAP_A:
- case SHL_A:
- case ROL_A:
- case SHR_A:
- case ROR_A:
- case PASS_A:
- // Set the Negative Flag
- if(result & 0x8000)
- flags |= N_FLAG;
- else
- flags &= ~N_FLAG;
-
- // Set the Zero Flag
- if(result & 0xffff)
- flags &= ~Z_FLAG;
- else
- flags |= Z_FLAG;
- break;
-
- default:
- break;
- }
- return(result & 0xffff);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Test the given Condition Code and returns true if it passes
- ///////////////////////////////////////////////////////////////////////////////
- int ALU::TestConditionCode(ALUConditionCode cc, const char* &description)
- {
- switch(cc)
- {
- case CC_VC: // overflow clear
- description=".VC";
- return(!(flags & V_FLAG));
-
- case CC_PL: // plus
- description=".PL";
- return(!(flags & N_FLAG));
-
- case CC_GE: // greater than or equal (signed)
- description=".GE";
- return(((flags & N_FLAG) && (flags & V_FLAG)) ||
- (!(flags & N_FLAG) && !(flags & V_FLAG)));
-
- case CC_F: // false
- description=".F";
- return 0;
-
- case CC_LE: // less than or equal (signed)
- description=".LE";
- return((flags & Z_FLAG) || ((flags & N_FLAG) && !(flags & V_FLAG)) ||
- (!(flags & N_FLAG) && (flags & V_FLAG)));
-
- case CC_NE: // not equal
- description=".NE";
- return(!(flags & Z_FLAG));
-
- case CC_LS: // less than or same (unsigned)
- description=".LS";
- return((flags & C_FLAG) || (flags & Z_FLAG));
-
- case CC_CC: // carry clear
- description=".CC";
- return(!(flags & C_FLAG));
-
- case CC_VS: // overflow set
- description=".VS";
- return(flags & V_FLAG);
-
- case CC_MI: // minus
- description=".MI";
- return(flags & N_FLAG);
-
- case CC_LT: // less than (signed)
- description=".LT";
- return(((flags & N_FLAG) && !(flags & V_FLAG)) ||
- (!(flags & N_FLAG) && (flags & V_FLAG)));
-
- case CC_T: // true
- description=".T";
- return 1;
-
- case CC_GT: // greater than (signed)
- description=".GT";
- return(((flags & N_FLAG) && (flags & V_FLAG) && !(flags & Z_FLAG)) ||
- (!(flags & N_FLAG) && !(flags & V_FLAG) && !(flags & Z_FLAG)));
-
- case CC_EQ: // equal
- description=".EQ";
- return(flags & Z_FLAG);
-
- case CC_HI: // higher (unsigned)
- description=".HI";
- return(!(flags & C_FLAG) && !(flags & Z_FLAG));
-
- case CC_CS: // carry set
- description=".CS";
- return(flags & C_FLAG);
-
- default:
- description=".??";
- return(0);
- }
- }
-
-